package net.chenlin.dp.ids.common.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;

/**
 * 随机串生成器
 * @author zhouchenglin[yczclcn@163.com]
 */
public class RandomKeyUtil {

    private static final Logger log = LoggerFactory.getLogger(RandomKeyUtil.class);

    private static RandomKeyUtil instance = new RandomKeyUtil();

    private String algorithm = "MD5";

    private Random random = new SecureRandom();

    private MessageDigest digest = null;

    /**
     * constructor
     */
    private RandomKeyUtil() {
        long seed = System.currentTimeMillis();
        char[] entropy = this.toString().toCharArray();
        for (int i = 0; i < entropy.length; ++i) {
            long update = (long)((byte)entropy[i] << i % 8 * 8);
            seed ^= update;
        }
        this.random.setSeed(seed);
    }

    /**
     * 生成16位随机字符串
     * @return
     */
    public static String nextKey() {
        return instance.generateId(16);
    }

    /**
     * 生成指定位数字符串
     * @param length
     * @return
     */
    private synchronized String generateId(int length) {
        byte[] buffer = new byte[length];
        StringBuilder reply = new StringBuilder();
        int resultLenBytes = 0;
        while (resultLenBytes < length) {
            this.random.nextBytes(buffer);
            buffer = this.getDigest().digest(buffer);
            for (int i = 0; i < buffer.length && resultLenBytes < length; ++i) {
                byte b1 = (byte)((buffer[i] & 240) >> 4);
                if (b1 < 10) {
                    reply.append((char)(48 + b1));
                } else {
                    reply.append((char)(65 + (b1 - 10)));
                }
                byte b2 = (byte)(buffer[i] & 15);
                if (b2 < 10) {
                    reply.append((char)(48 + b2));
                } else {
                    reply.append((char)(65 + (b2 - 10)));
                }
                ++resultLenBytes;
            }
        }
        return reply.toString();
    }

    public synchronized String getAlgorithm() {
        return this.algorithm;
    }

    public synchronized void setAlgorithm(String algorithm) {
        this.algorithm = algorithm;
        this.digest = null;
    }

    private MessageDigest getDigest() {
        if (this.digest == null) {
            try {
                this.digest = MessageDigest.getInstance(this.algorithm);
            } catch (NoSuchAlgorithmException e) {
                log.error("getDigedt exception", e);
                try {
                    this.digest = MessageDigest.getInstance("MD5");
                } catch (NoSuchAlgorithmException ee) {
                    this.digest = null;
                    throw new IllegalStateException("No algorithms for RandomKeyUtil", ee);
                }
            }
        }
        return this.digest;
    }

    public final String toStrig() {
        return super.toString();
    }

}
